package com.oro.backingbeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedProperty;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.oro.converters.ContattoScuolaStringConverter;
import com.oro.converters.SedeStringConverter;
import com.oro.domain.Banca;
import com.oro.domain.BankBranch;
import com.oro.domain.Categoria;
import com.oro.domain.ContattoScuola;
import com.oro.domain.Corso;
import com.oro.domain.Costo;
import com.oro.domain.Email;
import com.oro.domain.Fax;
import com.oro.domain.IndirizzoAU;
import com.oro.domain.MacroCategoria;
import com.oro.domain.Scuola;
import com.oro.domain.Sede;
import com.oro.domain.Telephone;
import com.oro.domain.User;
import com.oro.domain.test.Foo;
import com.oro.service.StudentService;
import com.oro.util.FacesUtils;

public class InserisciScuolaBean implements Serializable {

	private static final Logger logger = Logger
			.getLogger(InserisciUtenteBean.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = 4554229353231216602L;

	private List<SelectItem> branchContactOptions;
	private Collection<Sede> branches;

	private Sede branchInput;
	private List<SelectItem> branchOptions;
	private Email contactEmailToRemove;
	private Fax contactFaxToRemove;
	private ContattoScuola contactInput;
	private String contactInputBranchName;
	private Collection<ContattoScuola> contacts;
	private Telephone contactTelephoneToRemove;
	private ContattoScuolaStringConverter contattoScuolaStringConverter;
	private Costo costToRemove;
	private Corso courseInput;
	private List<String> courseInputBranchesNames;
	private Long courseInputCategoryId;

	private Long courseInputMacroCategoryId;
	private List<Corso> courses;
	private Email emailToRemove;
	private List<SelectItem> emailTypeOptions;

	private Fax faxToRemove;
	private Collection<Foo> foos;
	private List<SelectItem> phoneCountryOptions;
	private List<SelectItem> phoneTypeOptions;
	private Scuola schoolInput;
	private Scuola schoolOutput;
	private SedeStringConverter sedeStringConverter;

	private List<SelectItem> stateOptions;

	private String schoolInputBankName;

	private List<SelectItem> numWeeksOptions;

	/**
	 * This will be injected when coming from a list page.
	 */
	@ManagedProperty("#{param.id}")
	private Long id;

	@Autowired
	private StudentService studentService;

	private Telephone telephoneToRemove;
	private Foo tempFoo;

	private List<String> townsAutoComplete;
	private List<String> bankNamesAutoComplete;

	private Banca bankInput;
	private BankBranch bankBranchInput;

	public InserisciScuolaBean() {

	}

	public boolean addEmptyContactEmail() {
		contactInput.add(new Email());
		return true;
	}

	public boolean addEmptyContactFax() {
		contactInput.add(new Fax());
		return true;
	}

	public boolean addEmptyContactPhone() {
		contactInput.add(new Telephone());
		return true;
	}

	public boolean addEmptyCost() {
		Costo newCost = new Costo();
		newCost.setCourse(courseInput);
		courseInput.add(newCost);
		return true;
	}

	public boolean addEmptyEmail() {
		schoolInput.add(new Email());
		return true;
	}

	public boolean addEmptyFax() {
		schoolInput.add(new Fax());
		return true;
	}

	public boolean addEmptyPhone() {
		schoolInput.add(new Telephone());
		return true;
	}

	public void addNewFoo() {
		// foos.add(new Foo(tempFoo.getTemp()));
		foos.add(tempFoo);
		tempFoo = new Foo();
	}

	public void addSchoolInputBranch() {
		Sede newBranch = new Sede();
		schoolInput.add(newBranch);
		newBranch.setSchool(schoolInput);
	}

	public void addSchoolInputContact() {
		ContattoScuola newContact = new ContattoScuola();
		newContact.setSchool(schoolInput);
		schoolInput.getContattiDiRiferimento().add(newContact);
		updateBranchContactOptions();
	}

	public void addSchoolInputCourse() {
		Corso course = new Corso();
		course.setSchool(schoolInput);
		schoolInput.getCourses().add(course);
	}

	public List<String> completeTownAu(String value) {
		List<String> result = new ArrayList<String>();
		for (String town : townsAutoComplete) {
			if (town != null)
				if (town.startsWith(value))
					result.add(town);
		}
		return result;
	}

	public List<String> completeBankName(String value) {
		List<String> result = new ArrayList<String>();
		for (String name : bankNamesAutoComplete) {
			if (name != null)
				if (name.startsWith(value))
					result.add(name);
		}
		return result;
	}

	public List<SelectItem> getBranchContactOptions() {
		branchContactOptions = new ArrayList<SelectItem>();
		for (ContattoScuola cs : schoolInput.getContattiDiRiferimento()) {
			branchContactOptions.add(new SelectItem(cs, cs.getFirstName() + " "
					+ cs.getSurname()));
		}
		return branchContactOptions;
	}

	public Collection<Sede> getBranches() {
		return branches;
	}

	public Sede getBranchInput() {
		return branchInput;
	}

	public List<SelectItem> getBranchOptions() {
		branchOptions = new ArrayList<SelectItem>();
		for (Sede s : schoolInput.getBranches()) {
			branchOptions.add(new SelectItem(s, s.getName()));
		}
		return branchOptions;
	}

	public List<Categoria> getCategories() {
		List<Categoria> cats = studentService
				.getCategoriesByMacroCategoryId(courseInputMacroCategoryId);
		return cats;
	}

	public Email getContactEmailToRemove() {
		return contactEmailToRemove;
	}

	public Fax getContactFaxToRemove() {
		return contactFaxToRemove;
	}

	public ContattoScuola getContactInput() {
		return contactInput;
	}

	public String getContactInputBranchName() {
		return contactInputBranchName;
	}

	public Collection<ContattoScuola> getContacts() {
		return contacts;
	}

	public Telephone getContactTelephoneToRemove() {
		return contactTelephoneToRemove;
	}

	public ContattoScuolaStringConverter getContattoScuolaStringConverter() {
		contattoScuolaStringConverter.setContattiScuola(schoolInput
				.getContattiDiRiferimento());
		return contattoScuolaStringConverter;
	}

	public Costo getCostToRemove() {
		return costToRemove;
	}

	public List<Categoria> getCourseCategories() {
		List<Categoria> cats = new ArrayList<Categoria>();
		cats.add(Categoria.ELICOS_ENGLISH);
		cats.add(Categoria.VET_PROFESSIONAL);
		return cats;
	}

	public Corso getcourseInput() {
		return courseInput;
	}

	public List<String> getCourseInputBranchesNames() {
		return courseInputBranchesNames;
	}

	public Long getCourseInputCategoryId() {
		return courseInputCategoryId;
	}

	public Long getCourseInputMacroCategoryId() {
		return courseInputMacroCategoryId;
	}

	public List<Corso> getCourses() {
		return courses;
	}

	public Sede getCreateEmptyBranch() {
		return new Sede();
	}

	public Email getEmailToRemove() {
		return emailToRemove;
	}

	public List<SelectItem> getEmailTypeOptions() {
		return emailTypeOptions;
	}

	public Fax getFaxToRemove() {
		return faxToRemove;
	}

	public Collection<Foo> getFoos() {
		return foos;
	}

	private Logger getLogger() {
		return logger;
	}

	public List<MacroCategoria> getMacrocategories() {
		return studentService.getMacroCategories();
	}

	public List<SelectItem> getPhoneCountryOptions() {
		return phoneCountryOptions;
	}

	public List<SelectItem> getPhoneTypeOptions() {
		return phoneTypeOptions;
	}

	public Scuola getSchoolInput() {
		return schoolInput;
	}

	public Scuola getSchoolOutput() {
		return schoolOutput;
	}

	public SedeStringConverter getSedeStringConverter() {
		sedeStringConverter.setSedi(schoolInput.getBranches());
		return sedeStringConverter;
	}

	public List<SelectItem> getStateOptions() {
		return stateOptions;
	}

	public StudentService getStudentService() {
		return studentService;
	}

	public Telephone getTelephoneToRemove() {
		return telephoneToRemove;
	}

	public Foo getTempFoo() {
		return tempFoo;
	}

	public List<String> getTownsAutoComplete() {
		return townsAutoComplete;
	}

	@PostConstruct
	public void postConstruct() {
		/*
		 * If it comes from a list page
		 */
		getLogger().info("School id = " + id);
		
		if (id != null && id != 0L) {
			schoolInput = studentService.getSchool(id);
		} else {
			schoolInput = new Scuola();
		}

		courseInput = new Corso();
		branchInput = new Sede();
		contactInput = new ContattoScuola();
		bankInput = new Banca();
		bankBranchInput = new BankBranch();
		courseInputMacroCategoryId = getMacrocategories().get(0).getId();

		branches = new ArrayList<Sede>();
		contacts = new ArrayList<ContattoScuola>();
		courses = new ArrayList<Corso>();
		courseInputBranchesNames = new ArrayList<String>();

		tempFoo = new Foo();
		foos = new ArrayList<Foo>();

		emailTypeOptions = new ArrayList<SelectItem>();
		for (String type : Email.getTypes()) {
			emailTypeOptions.add(new SelectItem(type, type));
		}
		phoneTypeOptions = new ArrayList<SelectItem>();
		for (String type : Telephone.getTypes()) {
			phoneTypeOptions.add(new SelectItem(type, type));
		}
		phoneCountryOptions = new ArrayList<SelectItem>();
		for (String country : Telephone.getCountries()) {
			phoneCountryOptions.add(new SelectItem(country, country));
		}
		stateOptions = new ArrayList<SelectItem>();
		for (String state : IndirizzoAU.getAustralianStates()) {
			stateOptions.add(new SelectItem(state, state));
		}
		branchOptions = new ArrayList<SelectItem>();
		for (Sede s : schoolInput.getBranches()) {
			branchOptions.add(new SelectItem(s, s.getName()));
		}
		numWeeksOptions = new ArrayList<SelectItem>();
		for (int i = 4; i <= 52; i++) {
			numWeeksOptions.add(new SelectItem(String.valueOf(i), String.valueOf(i)));
		}
		// addEmptyEmail();
		// addEmptyPhone();
		// addEmptyFax();
		branchContactOptions = new ArrayList<SelectItem>();
		for (ContattoScuola cs : schoolInput.getContattiDiRiferimento()) {
			branchContactOptions.add(new SelectItem(cs, cs.getFirstName() + " "
					+ cs.getSurname()));
		}
		townsAutoComplete = studentService.getTownsAu();
		bankNamesAutoComplete = studentService.getBankNames();
		getLogger().info("InserisciScuolaBeen has been constructed.");
	}

	@PreDestroy
	public void preDestroy() {
		getLogger().info("InserisciScuolaBeen is being destroyed.");
	}

	public boolean removeContactEmail() {
		return contactInput.remove(contactEmailToRemove);
	}

	public boolean removeContactFax() {
		return contactInput.remove(contactFaxToRemove);
	}

	public boolean removeContactTelephone() {
		return contactInput.remove(contactTelephoneToRemove);
	}

	public boolean removeCourseInputCost() {
		return courseInput.remove(costToRemove);
	}

	public boolean removeEmail() {
		return schoolInput.remove(emailToRemove);
	}

	private void removeEmptyEmails() {
		Email e;
		for (Iterator<Email> it = schoolInput.getEmails().iterator(); it
				.hasNext();) {
			e = it.next();
			if (e.getEmail() == null || e.getEmail() == "") {
				it.remove();
			}
		}
	}

	private void removeEmptyFaxes() {
		Fax e;
		for (Iterator<Fax> it = schoolInput.getFaxes().iterator(); it.hasNext();) {
			e = it.next();
			if (e.getNumber() == null || e.getNumber() == "") {
				it.remove();
			}
		}

	}

	private void removeEmptyTelephones() {
		Telephone e;
		for (Iterator<Telephone> it = schoolInput.getTelephones().iterator(); it
				.hasNext();) {
			e = it.next();
			if (e.getNumber() == null || e.getNumber() == "") {
				it.remove();
			}
		}

	}

	public boolean removeFax() {
		return schoolInput.remove(faxToRemove);
	}

	public boolean removeTelephone() {
		return schoolInput.remove(telephoneToRemove);
	}

	public void reset(ActionEvent e) {
		postConstruct();
	}

	public void resetBranchInput() {
		branchInput = new Sede();
	}

	public void resetContactInput() {
		contactInput = new ContattoScuola();
	}

	public void setBranchContactOptions(List<SelectItem> branchContactOptions) {
		this.branchContactOptions = branchContactOptions;
	}

	public void setBranches(Collection<Sede> branches) {
		this.branches = branches;
	}

	public void setBranchInput(Sede branchInput) {
		this.branchInput = branchInput;
	}

	public void setBranchOptions(List<SelectItem> branchOptions) {
		this.branchOptions = branchOptions;
	}

	public void setContactEmailToRemove(Email contactEmailToRemove) {
		this.contactEmailToRemove = contactEmailToRemove;
	}

	public void setContactFaxToRemove(Fax contactFaxToRemove) {
		this.contactFaxToRemove = contactFaxToRemove;
	}

	public void setContactInput(ContattoScuola contactInput) {
		this.contactInput = contactInput;
	}

	public void setContactInputBranchName(String contactInputBranchName) {
		this.contactInputBranchName = contactInputBranchName;
	}

	public void setContacts(Collection<ContattoScuola> contacts) {
		this.contacts = contacts;
	}

	public void setContactTelephoneToRemove(Telephone contactTelephoneToRemove) {
		this.contactTelephoneToRemove = contactTelephoneToRemove;
	}

	public void setContattoScuolaStringConverter(
			ContattoScuolaStringConverter contattoScuolaStringConverter) {
		this.contattoScuolaStringConverter.setContattiScuola(schoolInput
				.getContattiDiRiferimento());
		this.contattoScuolaStringConverter = contattoScuolaStringConverter;
	}

	public void setCostToRemove(Costo costToRemove) {
		this.costToRemove = costToRemove;
	}

	public void setcourseInput(Corso courseInput) {
		this.courseInput = courseInput;
	}

	public void setCourseInputBranchesNames(
			List<String> courseInputBranchesNames) {
		this.courseInputBranchesNames = courseInputBranchesNames;
	}

	public void setCourseInputCategoryId(Long courseInputCategoryId) {
		this.courseInputCategoryId = courseInputCategoryId;
	}

	public void setCourseInputMacroCategoryId(Long courseInputMacroCategoryId) {
		this.courseInputMacroCategoryId = courseInputMacroCategoryId;
	}

	public void setCourses(List<Corso> courses) {
		this.courses = courses;
	}

	public void setEmailToRemove(Email emailToRemove) {
		this.emailToRemove = emailToRemove;
	}

	public void setEmailTypeOptions(List<SelectItem> emailTypeOptions) {
		this.emailTypeOptions = emailTypeOptions;
	}

	public void setFaxToRemove(Fax faxToRemove) {
		this.faxToRemove = faxToRemove;
	}

	public void setFoos(Collection<Foo> foos) {
		this.foos = foos;
	}

	public void setPhoneCountryOptions(List<SelectItem> phoneCountryOptions) {
		this.phoneCountryOptions = phoneCountryOptions;
	}

	public void setPhoneTypeOptions(List<SelectItem> phoneTypeOptions) {
		this.phoneTypeOptions = phoneTypeOptions;
	}

	public void setSchoolInput(Scuola schoolInput) {
		this.schoolInput = schoolInput;
		/*
		 * If this comes from a list of students and we want to edit him.
		 */
		if (getSchoolInput().getId() != null && getSchoolInput().getId() != 0L) {

			studentService.prepare(schoolInput);

		}
	}

	public void setSchoolOutput(Scuola schoolOutput) {
		this.schoolOutput = schoolOutput;
	}

	public void setSedeStringConverter(SedeStringConverter sedeStringConverter) {
		this.sedeStringConverter.setSedi(schoolInput.getBranches());
		this.sedeStringConverter = sedeStringConverter;
	}

	public void setStateOptions(List<SelectItem> stateOptions) {
		this.stateOptions = stateOptions;
	}

	public void setStudentService(StudentService studentService) {
		this.studentService = studentService;
	}

	public void setTelephoneToRemove(Telephone telephoneToRemove) {
		this.telephoneToRemove = telephoneToRemove;
	}

	public void setTempFoo(Foo tempFoo) {
		this.tempFoo = tempFoo;
	}

	public void setTownsAutoComplete(List<String> townsAutoComplete) {
		this.townsAutoComplete = townsAutoComplete;
	}

	public String submit() {
		// At this point, Corso's branches collection is populated.
		// Corso is not the owner of the relation.
		// But saving schoolInput will save Sede, which is the owner.
		// We have to populate Sede's courses collection, otherwise the relation
		// will not be persisted.
		for (Sede s : schoolInput.getBranches()) {
			if (s != null) {
				for (Corso c : schoolInput.getCourses()) {
					if (c != null) {
						if (c.getSedi().contains(s)) {
							s.add(c);
						}
					}
				}
			}
		}

		for (Sede s : schoolInput.getBranches()) {
			System.out.println("Branch: " + s.getName());
			for (Corso c : s.getCorsi())
				System.out.println("Corso: " + c.getName());
		}

		for (Corso c : schoolInput.getCourses()) {
			System.out.println("Course: " + c.getName());
			for (Sede s : c.getSedi())
				System.out.println("Sede: " + s.getName());
		}

		schoolInput.setBank(studentService.getBankByName(schoolInputBankName));

		Object u = FacesUtils.getLoggedUser();
		if (u != null & u instanceof User && schoolInput.getAdder() == null)
			schoolInput.setAdder((User) u);

		try {
			studentService.save(schoolInput);
		} catch (Exception e) {
			e.printStackTrace();
			return "inserisciScuolaFail";
		}

		schoolOutput = schoolInput;
		schoolInput = new Scuola();

		return "inserisciScuolaSuccess";
	}

	public void submitNewBranch() {
		branchInput.setSchool(schoolInput);
		schoolInput.add(branchInput);
		branchInput = new Sede();
		updateBranchOptions();
	}

	public void submitNewContact() {
		System.out
				.println("contactInputBranchName = " + contactInputBranchName);
		// Set the branch. Because h:selectItem accepts only values of built-in
		// types :(
		// We assume the branches names to be unique within the list
		for (Sede s : schoolInput.getBranches()) {
			if (s.getName().equals(contactInputBranchName)) {
				System.out.println("FOUND BRANCH");
				s.add(contactInput);
				break;
			}
		}
		// Set the school.
		contactInput.setSchool(schoolInput);
		schoolInput.add(contactInput);
		// Reset contactInput.
		contactInput = new ContattoScuola();
	}

	public void submitNewCourse() {
		// we are temporarily storing the now courses in the 'courses' list.
		// so, when we submit the new course, we add it to the list.
		// At this point, we have a courseInput and a list of String,
		// representing the course's branches.
		// This method analyses that list and associates the courseInput to the
		// proper branches.

		// It is assumed that the branches names are unique within the list, and
		// every branch has a name.
		boolean found = false;
		for (String s : courseInputBranchesNames) {
			if (s != null) {
				for (Sede sede : schoolInput.getBranches()) {
					if (s.equals(sede.getName())) {
						found = true;
						courseInput.add(sede);
						if (!sede.getCorsi().contains(courseInput))
							sede.add(courseInput);
					}
				}
			}
		}
		System.out.println("Course " + courseInput.getName() + "'s branches: ");
		for (Sede s : courseInput.getSedi())
			System.out.println(s.getName());
		System.out.println("Course " + courseInput.getName() + "'s costs: ");
		for (Costo s : courseInput.getCosti())
			System.out.println(s.getWeeklyPrice());
		// We also have the category id and set the proper category.
		courseInput.setCategoria(studentService
				.getCategory(courseInputCategoryId));
		// Finally, we add the course to the collection.
		if (found)
			courses.add(courseInput);
		// Reset courseInput.
		courseInput = new Corso();
	}

	public void updateBranchContactOptions() {
		branchContactOptions = new ArrayList<SelectItem>();
		for (ContattoScuola cs : schoolInput.getContattiDiRiferimento()) {
			branchContactOptions.add(new SelectItem(cs, cs.getFirstName() + " "
					+ cs.getSurname()));
		}
	}

	public void updateBranchOptions() {
		branchOptions = new ArrayList<SelectItem>();
		for (Sede s : schoolInput.getBranches()) {
			branchOptions.add(new SelectItem(s, s.getName()));
		}
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Long getId() {
		return id;
	}

	public void setSchoolInputBankName(String schoolInputBankName) {
		this.schoolInputBankName = schoolInputBankName;
	}

	public String getSchoolInputBankName() {
		return schoolInputBankName;
	}

	public void setBankNamesAutoComplete(List<String> bankNamesAutoComplete) {
		this.bankNamesAutoComplete = bankNamesAutoComplete;
	}

	public List<String> getBankNamesAutoComplete() {
		return bankNamesAutoComplete;
	}

	public List<Banca> getBanks() {
		return studentService.getBanks();
	}

	public List<SelectItem> getBanksOptions() {
		List<SelectItem> result = new ArrayList<SelectItem>();
		result.add(new SelectItem(null, "N/A"));
		for (Banca b : getBanks()) {
			result.add(new SelectItem(b, b.getName()));
		}
		return result;
	}

	public void setBankInput(Banca bankInput) {
		this.bankInput = bankInput;
	}

	public Banca getBankInput() {
		return bankInput;
	}

	public void submitBank() {
		studentService.save(bankInput);
		schoolInput.setBank(studentService.getBank(bankInput.getId()));
		bankInput = new Banca();
	}

	public void submitBankBranch() {
		if (schoolInput.getBank() != null) {
			bankBranchInput.setBank(schoolInput.getBank());
			studentService.save(bankBranchInput);
			schoolInput.setBankBranch(studentService
					.getBankBranch((bankBranchInput).getId()));
			schoolInput
					.getBank()
					.getBranches()
					.add(studentService.getBankBranch((bankBranchInput).getId()));
			bankBranchInput = new BankBranch();
		}
	}

	public void setBankBranchInput(BankBranch bankBranchInput) {
		this.bankBranchInput = bankBranchInput;
	}

	public BankBranch getBankBranchInput() {
		return bankBranchInput;
	}

	public List<BankBranch> getBankBranches() {
		return studentService.getBankBranches(schoolInput.getBank());
	}

	public List<SelectItem> getBankBranchesOptions() {
		List<SelectItem> result = new ArrayList<SelectItem>();
		result.add(new SelectItem(null, "N/A"));
		for (BankBranch b : getBankBranches()) {
			result.add(new SelectItem(b, b.getIndirizzo().getIndirizzoLinea1()
					+ ", " + b.getIndirizzo().getCitta()));
		}
		return result;
	}

	public List<SelectItem> getNumWeeksOptions() {
		return numWeeksOptions;
	}

	public void setNumWeeksOptions(List<SelectItem> numWeeksOptions) {
		this.numWeeksOptions = numWeeksOptions;
	}
}
